/*
 * Created on Sep 4, 2005
 */
package bancosys.tec.persist.persister;

import java.util.List;

import jmine.tec.persist.PersistMessages;

import org.hibernate.HibernateException;

import bancosys.tec.persist.Persistable;
import bancosys.tec.persist.exception.PersistenceException;
import bancosys.tec.persist.validator.ValidationError;
import bancosys.tec.persist.validator.ValidationException;
import bancosys.tec.persist.validator.Validator;

/**
 * Classe implementadora da interface Persister, tendo como função delegar a persistência para o Hibernate.
 * <p>
 * É responsabilidade do hibernate executar a persistência através dos métodos equivalentes na Session. Cabe aos implementadores do adapter
 * recuperar a Session, seja utilizando o próprio SessionFactory, ou classes utilitárias dos frameworks acessórios, como SessionFactoryUtils
 * do spring.
 * <p>
 * As aplicações utilizam classes específicas derivadas dessa classe base. Essa classe é utilizada diretamente apenas para executar testes.
 * <p>
 * É responsabilidade das classes derivadas executar o controle transacional, ou do cliente do PersistAdapter garantir a transacionalidade
 * da execução dos métodos.
 * <p>
 * <b> <i> Classes que extendem essa classe base: </i> </b>
 * {@link auth.bancosys.tec.persist.hibernate.domain.persist.impl.spring.SpringPersistAdapter SpringPersistAdapter}
 * 
 * @author Frank Cara
 * @see bancosys.tec.persist.persister.Persister
 * @param <T> classe do bean.
 */
public class BasePersistAdapter<T extends Persistable> extends AbstractPersister<T> {

    // ---------------------------------
    // ----- Persister methods -----

    /**
     * Salva.
     */
    public void save() {
        T bean = this.getTarget();
        try {
            Validator<T> validator = this.getValidator();
            if (PersistenceAction.insert.equals(this.insertOrUpdate())) {
                this.beforeSave(validator, bean);
                this.getSession().saveOrUpdate(bean);
                this.afterSave(validator, bean);
            } else {
                this.beforeUpdate(validator, bean);
                this.getSession().saveOrUpdate(bean);
                this.afterUpdate(validator, bean);
            }
        } catch (HibernateException e) {
            throw new PersistenceException(PersistMessages.ERROR_SAVING_BEAN.create(bean.getClass().getName()), e);
        }
    }

    /**
     * Como esse adapter não é utilizado para entidades autorizáveis, faz o mesmo que {@link BasePersistAdapter#save()}.
     * 
     * @param authAction não é utilizado.
     */
    public void save(Object authAction) {
        this.save();
    }

    /**
     * Remove.
     */
    public void remove() {
        T bean = this.getTarget();
        try {
            Validator<T> validator = this.getValidator();
            this.beforeRemove(validator, bean);
            this.getSession().delete(bean);
            this.afterRemove(validator, bean);
        } catch (HibernateException e) {
            throw new PersistenceException(PersistMessages.ERROR_REMOVING_BEAN.create(bean.getClass().getName()));
        }
    }

    // ========= hooks before/after

    /**
     * Chamado após salvar.
     * 
     * @param validator validador.
     * @param bean objeto manipulado.
     */
    protected final void afterSave(Validator validator, T bean) {
        this.fireAfterInsert(bean, null);
    }

    /**
     * Chamado antes de salvar.
     * 
     * @param validator validador.
     * @param bean objeto manipulado.
     */
    protected final void beforeSave(Validator<T> validator, T bean) {
        List<ValidationError> errors = validator.validateInsert(bean);
        if (errors != null && !errors.isEmpty()) {
            throw new ValidationException(errors);
        }
        this.fireBeforeInsert(bean, null);
    }

    /**
     * Chamado após salvar.
     * 
     * @param validator validador.
     * @param bean objeto manipulado.
     */
    protected final void afterUpdate(Validator<T> validator, T bean) {
        this.fireAfterUpdate(bean, null);
    }

    /**
     * Chamado antes de atualizar.
     * 
     * @param bean objeto manipulado.
     * @param validator validador.
     */
    protected final void beforeUpdate(Validator<T> validator, T bean) {
        List<ValidationError> errors = validator.validateUpdate(bean);
        if (errors != null && !errors.isEmpty()) {
            throw new ValidationException(errors);
        }
        this.fireBeforeUpdate(bean, null);
    }

    /**
     * Chamado após remover.
     * 
     * @param validator validador.
     * @param bean objeto manipulado.
     */
    protected final void afterRemove(Validator<T> validator, T bean) {
        this.fireAfterRemove(bean);
    }

    /**
     * Chamado antes de remover.
     * 
     * @param validator validador.
     * @param bean objeto manipulado.
     */
    protected final void beforeRemove(Validator<T> validator, T bean) {
        List<ValidationError> errors = validator.validateRemove(bean);
        if (errors != null && !errors.isEmpty()) {
            throw new ValidationException(errors);
        }
        this.fireBeforeRemove(bean);
    }

    /**
     * Devolve <code>false</code>, indicando que o dado não é autorizável.
     * 
     * @return <code>false</code>, indicando que o dado não é autorizável.
     */
    public boolean isAuthorizable() {
        return false;
    }
}